// - interface
// - map
// - 发布系统，能发布k8s node(jtype字段) 不同的类型的任务
// - 增量更新：开启新的，停掉旧的
// - 原有的是a,b,c ，b,c,d --> 开启d, 停掉a
package main

import (
	"fmt"
	"log"
	"sync"
	"time"
)

//Publisher接口，结构体需要实现以下的增删改查方法
type Publisher interface {
	Getjob(id int) (bool, string, string)
	Listjob()
	Startjob(name string, content string)
	Stopjob(id int) bool
	StartMultijob(jobs map[string]string)
}

//自定义类型结构体，里面可绑定不同类型的独有方法，相同的方法放在匿名结构体中
type K8s struct {
	Publish
}
type Node struct {
	Publish
}

//map中的实际数据放在这里
type Content struct {
	JobName    string
	JobContent string
}

//上面的匿名结构体，实际上是一个线程安全的map
type Publish struct {
	sync.RWMutex
	JobMap map[int]*Content
}

//查询方法，传入任务id，返回任务是否存在，任务名称、任务内容
func (k *K8s) Getjob(id int) (bool, string, string) {
	k.RLock()
	defer k.RUnlock()
	if k.Publish.JobMap[id] != nil {
		return true, k.Publish.JobMap[id].JobName, k.Publish.JobMap[id].JobContent
	} else {
		return false, fmt.Sprintf("此K8S任务ID[%d]不存在\n", id), fmt.Sprintf("此ID[%d]不存在\n", id)
	}
}

//遍历，加读锁
func (k *K8s) Listjob() {
	k.RLock()
	defer k.RUnlock()
	for k, v := range k.Publish.JobMap {
		log.Printf("K8S中任务ID为[%d]，任务名称为%v，任务内容为%v", k, v.JobName, v.JobContent)
	}
}

//单独开新任务，传入任务名称和内容，根据当前map中的任务数新增计数，加读写锁
func (k *K8s) Startjob(name string, content string) {
	jobnum := len(k.Publish.JobMap)
	k.Lock()
	k.Publish.JobMap[jobnum+1] = &Content{
		JobName:    name,
		JobContent: content,
	}
	k.Unlock()
}

//根据任务id停任务
func (k *K8s) Stopjob(id int) bool {
	exist, _, _ := k.Getjob(id)
	if exist {
		k.Lock()
		delete(k.Publish.JobMap, id)
		k.Unlock()
		return true
	} else {
		log.Printf("[该K8S任务ID[%d]未开启，请检查]\n", id)
		return false
	}
}

//传入新的map作为任务列表，遍历后调用上面的方法开任务
func (k *K8s) StartMultijob(jobs map[string]string) {
	for key1, value1 := range jobs {
		flag := false
		for key, value := range k.Publish.JobMap {
			if key1 == k.Publish.JobMap[key].JobName {
				log.Printf("K8S任务ID为[%d]的任务已存在，将不会被重复执行，K8S任务名称为%v，K8S任务内容为%v", key, value.JobName, value.JobContent)
				flag = true
			}
		}
		if !flag {
			k.Startjob(key1, value1)
		}
	}
}

func (n *Node) Getjob(id int) (bool, string, string) {
	n.RLock()
	defer n.RUnlock()
	if n.Publish.JobMap[id] != nil {
		return true, n.Publish.JobMap[id].JobName, n.Publish.JobMap[id].JobContent
	} else {
		return false, fmt.Sprintf("此Node任务ID[%d]不存在\n", id), fmt.Sprintf("此Node任务ID[%d]不存在\n", id)
	}
}

func (n *Node) Listjob() {
	n.RLock()
	defer n.RUnlock()
	for k, v := range n.Publish.JobMap {
		log.Printf("Node中任务ID为[%d]，Node任务名称为%v，Node任务内容为%v", k, v.JobName, v.JobContent)
	}
}

func (n *Node) Startjob(name string, content string) {
	jobnum := len(n.Publish.JobMap)
	n.Lock()
	n.Publish.JobMap[jobnum+1] = &Content{
		JobName:    name,
		JobContent: content,
	}
	n.Unlock()
}

func (n *Node) Stopjob(id int) bool {
	exist, _, _ := n.Getjob(id)
	if exist {
		n.Lock()
		delete(n.Publish.JobMap, id)
		n.Unlock()
		return true
	} else {
		log.Printf("[该Node任务ID[%d]未开启，请检查]\n", id)
		return false
	}
}

func (n *Node) StartMultijob(jobs map[string]string) {
	for key1, value1 := range jobs {
		flag := false
		for key, value := range n.Publish.JobMap {
			if key1 == n.Publish.JobMap[key].JobName {
				log.Printf("任务ID为[%d]的Node任务已存在，将不会被重复执行，Node任务名称为%v，Node任务内容为%v", key, value.JobName, value.JobContent)
				flag = true
			}
		}
		if !flag {
			n.Startjob(key1, value1)
		}
	}
}

func main() {
	//初始化一个新的map作为批量传入的任务清单
	var job = make(map[string]Publisher)
	p := &Publish{
		JobMap: make(map[int]*Content),
	}
	k := &K8s{
		Publish: *p,
	}
	p1 := &Publish{
		JobMap: make(map[int]*Content),
	}
	n := &Node{
		Publish: *p1,
	}
	job["k8s"] = k
	job["node"] = n
	// exist, _, _ := k.Getjob(1)
	// fmt.Println(exist)
	for _, v := range job {
		v.Startjob("测试1", "测试代码")
		v.Startjob("测试2", "测试代码")
		v.Startjob("测试3", "测试代码")
	}
	var m = map[string]string{
		"测试1":   "测试多个任务1",
		"测试多个2": "测试多个任务2",
		"测试多个3": "测试多个任务3",
	}
	for _, v := range job {
		v.StartMultijob(m)
	}
	// for _, v := range job {
	// 	v.Listjob()
	// }
	time.Sleep(time.Second * 1)
	fmt.Println("==================================")
	time.Sleep(time.Second * 1)
	var test Publisher
	test = k
	test.Stopjob(2)
	test.Listjob()

	test = n
	test.Stopjob(1)
	test.Listjob()

}
// 可以